#ifndef _ISOC99_SOURCE
#define _ISOC99_SOURCE
#endif

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
#include "cal_file.h"

#define PI 3.141592653589793
#define DEG_PER_RAD 180.0 / PI
#define RAD_PER_DEG PI / 180.0

#define CAL_FILE "phasor_calib_data.txt"
#define TEMP_NAME "phasor_calib_xxxxxx.txt"

int ReadRecord(char *buffer, double *magnitude, double *mag_phase);
int WriteRecord(FILE *out_file, char *id_str, double *magnitude, double *mag_phase);

#ifdef TEST

double mag[MAX_CHANNELS] = {1, 3, 5, 7};
double phase[MAX_CHANNELS] = {2, 4, 6, 8};

int main(int argc, char *argv[]) {
    int arg;

    for (arg = 1; arg < argc; arg++) {
        mag[(arg - 1) >> 1] = strtof(argv[arg], 0);
        arg++;
        if (arg < argc) {
            phase[(arg - 1) >> 1] = strtof(argv[arg], 0);
        }
    }

    UpdateCalibrationFile(0, 1855000, mag, phase);
    for (arg = 0; arg < MAX_CHANNELS; arg++) {
        mag[arg] += 10.0;
        phase[arg] += 10.0;
    }
    UpdateCalibrationFile(0, 1655000, mag, phase);
    for (arg = 0; arg < MAX_CHANNELS; arg++) {
        mag[arg] = phase[arg] = 0.0;
    }
    ReadCalibrationFile(0, 1855000, mag, phase);
    return 0;
}
#endif

int ReadCalibrationFile(int type, int frequency, double *magnitude, double *mag_phase) {
    FILE *in_file;
    char buffer[180];
    char *cursor;
    char id_str[40];
    int i, result = 0;

    // convert type and frequency to id strings
    sprintf(id_str, "%s, %d", type ? "receiver" : "antenna", frequency);

    // apply default results, just in case
    for (i = 0; i < MAX_CHANNELS; i++) {
        magnitude[i] = 1.0;
        mag_phase[i] = 0.0;
    }

    // apply default file path if necessary
    if (cal_file_path == 0)
        cal_file_path = CAL_FILE;

    // open in file
    if ((in_file = fopen(cal_file_path, "r")) == 0) {
        fprintf(stderr, "Can't open calibration file \"%s\"\n", cal_file_path);
        return 1;
    }

    // file format:
    // frequency, ch 0 mag, ch 0 phase, ch 1 mag, ch 1 phase, ch 2 mag, ch 2 phase, ch 3 mag, ch 3 phase
    // frequency, ...
    //
    // phases are angles in degrees

    // read from the old file and find the line that matches the type and frequency we seek.
    cursor = fgets(buffer, sizeof(buffer), in_file);
    while (cursor) {
        if (strncmp(buffer, id_str, strlen(id_str)) == 0) {
            result = ReadRecord(buffer, magnitude, mag_phase);
        }
        cursor = fgets(buffer, sizeof(buffer), in_file);
    }

    // message
    fprintf(stderr, "Read %s\n", cal_file_path);

    // close files
    if (in_file) fclose(in_file);
    return result;
}

int UpdateCalibrationFile(int type, int frequency, double *magnitude, double *mag_phase) {
    FILE *in_file;
    FILE *out_file;
    char buffer[180];
    char *cursor;
    char id_str[40];
    int result = 0;
    char new_name[40];

    // convert type and frequency to id strings
    sprintf(id_str, "%s, %d", type ? "receiver" : "antenna", frequency);

    // rename old file
    strcpy(new_name, cal_file_path);
    strcat(new_name, "~");
    if (rename(cal_file_path, new_name)) {
        if (errno != ENOENT) {
            fprintf(stderr, "Couldn't rename \"%s\", error %s (%d)\n", cal_file_path, strerror(errno), errno);
            return 1;
        }
    }

    // apply default if necessary
    if (cal_file_path == 0)
        cal_file_path = CAL_FILE;

    // open in and out files
    in_file = fopen(new_name, "r");

    if ((out_file = fopen(cal_file_path, "w")) == 0) {
        fprintf(stderr, "Can't open \"%s\" for writing\n", cal_file_path);
        fclose (in_file);
        if (rename(new_name, cal_file_path) < 0) {
            fprintf(stderr, "Can't rename \"%s\" to \"%s\"\n", new_name, cal_file_path);
            return 3;
        }
        return 2;
    }

    // file format:
    // frequency, ch 0 mag, ch 0 phase, ch 1 mag, ch 1 phase, ch 2 mag, ch 2 phase, ch 3 mag, ch 3 phase
    // frequency, ...
    //
    // phases are angles in degrees

    // If the old file exists, read from the file and write the new file with the same contents,
    // except the line that matches the given type and frequency.
    if (in_file) {
        cursor = fgets(buffer, sizeof(buffer), in_file);
        while (cursor) {
            if (strncmp(buffer, id_str, strlen(id_str)) != 0) {
                fputs(buffer, out_file);
            }
            cursor = fgets(buffer, sizeof(buffer), in_file);
        }
    }

    result = WriteRecord(out_file, id_str, magnitude, mag_phase);

    // message
    if (in_file && out_file) {
        fprintf(stderr, "Rewrote %s\n", cal_file_path);
    } else {
        fprintf(stderr, "Wrote new %s\n", cal_file_path);
    }

    // close files
    if (in_file) fclose(in_file);
    if (out_file) fclose(out_file);

    // delete old file
    remove(new_name);
    return 0;
}

int ReadRecord(char *buffer, double *magnitude, double *mag_phase) {
    int i;
    int count;
    char type_str[40];
    int frequency;

    sscanf(buffer, "%[a-z], %d%n", type_str, &frequency, &count);
    for (i = 0; i < MAX_CHANNELS; i++) {
        buffer += count;
        sscanf(buffer, ", %le, %le%n", &magnitude[i], &mag_phase[i], &count);
        mag_phase[i] *= RAD_PER_DEG;
    }
    return 1;
}

int WriteRecord(FILE *out_file, char *id_str, double *magnitude, double *mag_phase) {
    int i;

    fprintf(out_file, "%s", id_str);
    for (i = 0; i < MAX_CHANNELS; i++) {
        fprintf(out_file, ", %4.3lf, %2.1lf", magnitude[i], mag_phase[i] * DEG_PER_RAD);
    }
    fprintf(out_file, "\n");
    return 1;
}
